﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace mrp16062010
{
    class GeriYukle
    {
        public string Id { get; set; }
        public static int nesneSayac;
        Cizelge cizelge;
        Rota.RotaParcasi rota;
        List<Rota.Operasyon> operasyon;
        DateTime baslangicTarihi;
        DateTime bitisTarihi;
        public bool IsYuklendi = false;
        int grupNo;
        private Tarih yuklemeTarihi=new Tarih();

        public Tarih YuklemeTarihi
        {
            get { return yuklemeTarihi; }
            set { yuklemeTarihi = value; }
        }

        private Siparis siparisBilgi;

        public Siparis SiparisBilgi
        {
            get { return siparisBilgi; }
            set { siparisBilgi = value; }
        }
        

        public GeriYukle(Cizelge gelenCizelge, Siparis gelenSiparis)
        {
            siparisBilgi = gelenSiparis;
            yuklemeTarihi.BitisTarihi = gelenSiparis.TarihBilgisi.BitisTarihi;
            mrp16062010.Yukle.sayac++;
            grupNo = mrp16062010.Yukle.sayac;
            cizelge = gelenCizelge;
            rota = siparisBilgi.Rota;
            baslangicTarihi = gelenSiparis.TarihBilgisi.BaslangicTarihi;
            bitisTarihi = gelenSiparis.TarihBilgisi.BitisTarihi;
            if (Ayarlar.Nesne.Karmala == true)
            {
                if (rota.TumSiralamalar == null)
                {
                    OptimumGeriYukle opt = new OptimumGeriYukle(rota);
                }
            }
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Kurucu();
            sw.Stop();
            string ExecutionTimeTaken = string.Format("Minutes :{0}\nSeconds :{1}\n Mili seconds :{2}", sw.Elapsed.Minutes, sw.Elapsed.Seconds, sw.Elapsed.TotalMilliseconds);
            //Console.Out.WriteLine(ExecutionTimeTaken);
        }

        public GeriYukle(Cizelge gelenCizelge, Tarih tarih, Rota.RotaParcasi gelenParca, Siparis gelenSiparis)
        {
            siparisBilgi = gelenSiparis;
            yuklemeTarihi.BitisTarihi = tarih.BitisTarihi;
            mrp16062010.Yukle.sayac++;
            grupNo = mrp16062010.Yukle.sayac;
            cizelge = gelenCizelge;
            rota = gelenParca;
            baslangicTarihi = tarih.BaslangicTarihi;
            bitisTarihi = tarih.BitisTarihi;

            //eğer ki bu rota parçası için önceden bir hesap yapılmamışsa optimum tabloları hesapla
            if (Ayarlar.Nesne.Karmala == true)
            {
                if (rota.TumSiralamalar == null)
                {
                    OptimumGeriYukle opt = new OptimumGeriYukle(rota);
                }
            }
            //Stopwatch sw = new Stopwatch();
            //sw.Start();
            //Kurucu();
            //sw.Stop();
            //string ExecutionTimeTaken = string.Format("Minutes :{0}\nSeconds :{1}\n Mili seconds :{2}", sw.Elapsed.Minutes, sw.Elapsed.Seconds, sw.Elapsed.TotalMilliseconds);
            //Console.Out.WriteLine(ExecutionTimeTaken);
        }

        private void Kurucu()
        {
            //Tüm sıralamaların yüzdesi alınmış adedi
            int toplamAdet=0;
            if (rota.TumSiralamalar!=null)
            {
                toplamAdet = rota.TumSiralamalar.Count;
            }
             
            //int alinacakAdet = Convert.ToInt32(((double)((double)Ayarlar.Nesne.OptimumYuklemeYuzdesi / (double)100)) * toplamAdet);
            int alinacakAdet = toplamAdet;
            if (alinacakAdet > 0)
            {
                //Bu yükleme şimdinin gerisine düşüyor mu?
                //Burada deneme olarak yüklenir eğer yükleme olabiliyorsa optimize yükleme denemelerine başlanır.
                //Yüklenemiyorsa yüklemeden tamamen çıkılır
                DateTime? sonTarihTest = Yukle(rota, bitisTarihi, 0);

                if (sonTarihTest.HasValue)
                {
                    cizelge.GeriAl(null, grupNo);
                }
                else
                {
                    IsYuklendi = false;
                    cizelge.GeriAl(null, grupNo);
                    return;
                }
                //
                //

                //Tüm olasılıklara göre yükleme yap
                int optIndex = -1;
                DateTime optBaslangicTarihi = DateTime.MaxValue;
                for (int i = 0; i < alinacakAdet; i++)
                {
                    DateTime? sonTarih = OptimumYukle(rota, bitisTarihi, 0, rota.TumSiralamalar[i].Siralama);
                    if (sonTarih.HasValue)
                    {
                        if (optBaslangicTarihi > sonTarih.Value)
                        {
                            optBaslangicTarihi = sonTarih.Value;
                            optIndex = i;
                        }
                        //baslangicTarihi = sonTarih.Value;//bitis tarihiydi baslangic olarak düzeltildi
                        //IsYuklendi = true;
                        //cizelge.Kaydet(null, grupNo);
                        //yuklemeTarihi.BaslangicTarihi = sonTarih.Value;
                    }
                    else
                    {
                        //IsYuklendi = false;
                    }
                    cizelge.GeriAl(null, grupNo);
                }
                if (optIndex > -1)
                {
                    DateTime? sonTarihSon = OptimumYukle(rota, bitisTarihi, 0, rota.TumSiralamalar[optIndex].Siralama);
                    if (sonTarihSon.HasValue)
                    {
                        baslangicTarihi = sonTarihSon.Value;//bitis tarihiydi baslangic olarak düzeltildi
                        IsYuklendi = true;
                        cizelge.Kaydet(null, grupNo);
                        yuklemeTarihi.BaslangicTarihi = sonTarihSon.Value;
                    }
                    else
                    {
                        IsYuklendi = false;
                        cizelge.GeriAl(null, grupNo);
                    }
                }
            }
            else
            {
                //herhangi bir siralaması yoksa
               
                DateTime? sonTarih = Yukle(rota, bitisTarihi, 0);
                
                if (sonTarih.HasValue)
                {
                    baslangicTarihi = sonTarih.Value;//bitis tarihiydi baslangic olarak düzeltildi
                    IsYuklendi = true;
                    cizelge.Kaydet(null, grupNo);
                    yuklemeTarihi.BaslangicTarihi = sonTarih.Value;
                }
                else
                {
                    IsYuklendi = false;
                    cizelge.GeriAl(null, grupNo);
                }
            }
        }
        /*
        public GeriYukle(Cizelge gelenCizelge, List<Rota.Operasyon> gelenOperasyon, DateTime gelenBaslangicTarihi, DateTime gelenBitisTarihi)
        {
            mrp16062010.Yukle.sayac++;
            grupNo = mrp16062010.Yukle.sayac;
            cizelge = gelenCizelge;
            operasyon = gelenOperasyon;
            baslangicTarihi = gelenBaslangicTarihi;
            bitisTarihi = gelenBitisTarihi;
            if (Yukle(operasyon, bitisTarihi, 0))
            {
                IsYuklendi = true;
                cizelge.Kaydet(null, grupNo);
            }
            else
            {
                IsYuklendi = false;
                cizelge.GeriAl(null, grupNo);
            }
        }*/


        private DateTime? Yukle(Rota.RotaParcasi rotaParcasi, DateTime gelenTarih, int recDerinlik)
        {
            DateTime sonTarih = DateTime.FromBinary(gelenTarih.ToBinary());
            foreach (Rota.Operasyon op in rotaParcasi.OperasyonList.Reverse<Rota.Operasyon>())
            {
                IsParcasi donenIsparcasi = Cizelge.ParcaEkle(cizelge, op, null, sonTarih, recDerinlik, grupNo, siparisBilgi);
                sonTarih = DateTime.FromBinary(donenIsparcasi.BasTarihi.ToBinary());
                if (sonTarih < this.baslangicTarihi)
                {
                    //Geri yüklenemiyor
                    return null;
                }
                else
                {
                    //yüklemeye devam
                    if (op.AltParca.Count > 0)
                    {
                        foreach (Rota.RotaParcasi rp in op.AltParca)
                        {
                            DateTime? deger = Yukle(rp, DateTime.FromBinary(sonTarih.ToBinary()), recDerinlik + 1);
                            if (deger.HasValue)
                            {
                                //Yüklendi
                                sonTarih = deger.Value;
                            }
                            else
                            {
                                //Yüklenemedi
                                return null;
                            }
                        }
                    }
                }
            }
            return sonTarih;
        }

        private DateTime? OptimumYukle(Rota.RotaParcasi rotaParcasi, DateTime gelenTarih, int recDerinlik, List<Rota.OptimumSiralama> siralamalar)
        {
            DateTime sonTarih = DateTime.FromBinary(gelenTarih.ToBinary());
            foreach (Rota.Operasyon op in rotaParcasi.OperasyonList.Reverse<Rota.Operasyon>())
            {
                IsParcasi donenIsparcasi = Cizelge.ParcaEkle(cizelge, op, null, sonTarih, recDerinlik, grupNo, siparisBilgi);
                sonTarih = DateTime.FromBinary(donenIsparcasi.BasTarihi.ToBinary());
                if (sonTarih < this.baslangicTarihi)
                {
                    //Geri yüklenemiyor
                    return null;
                }
                else
                {
                    //yüklemeye devam
                    if (op.AltParca.Count > 0)
                    {
                        Rota.OptimumSiralama siralama = (from x in siralamalar
                                                         where x.Ust == op
                                                         select x).FirstOrDefault();
                        IEnumerable<Rota.RotaParcasi> parcalar;
                        if (siralama!=null)
                        {
                            parcalar = siralama.Siralama;
                        }
                        else
                        {
                            parcalar = op.AltParca;
                        }

                        foreach (Rota.RotaParcasi rp in parcalar)
                        {
                            DateTime? deger = OptimumYukle(rp, DateTime.FromBinary(sonTarih.ToBinary()), recDerinlik + 1, siralamalar);
                            if (deger.HasValue)
                            {
                                //Yüklendi
                                sonTarih = deger.Value;
                            }
                            else
                            {
                                //Yüklenemedi
                                return null;
                            }
                        }
                    }
                }
            }
            return sonTarih;
        }
        
        ////Eski sistem permütasyon yöntemi
        //private DateTime? Yukle(Rota.RotaParcasi rotaParcasi, DateTime gelenTarih, int recDerinlik)
        //{
        //    DateTime sonTarih = DateTime.FromBinary(gelenTarih.ToBinary());
        //    foreach (Rota.Operasyon op in rotaParcasi.OperasyonList.Reverse<Rota.Operasyon>())
        //    {
        //        //Gelen rota parçasının operasyonlarını yükle
                
        //        IsParcasi donenIsparcasi = Cizelge.ParcaEkle(cizelge, op, null, sonTarih, recDerinlik, grupNo, siparisBilgi);
                
        //        sonTarih = DateTime.FromBinary(donenIsparcasi.BasTarihi.ToBinary());
        //        DateTime eldekiTarih = DateTime.FromBinary(donenIsparcasi.BasTarihi.ToBinary());
        //        if (sonTarih < this.baslangicTarihi)
        //        {
        //            //Geri yüklenemiyor
        //            return null;
        //        }
        //        else if (op.AltParca.Count > 0)
        //        {
        //            bool tekMi=true;
        //            int tekSay=0;
        //            foreach (Rota.RotaParcasi parca in op.AltParca)
        //            {
        //                tekSay++;
        //                if (parca.OperasyonList.Count > 0 && tekSay > 1)
        //                {
        //                    tekMi = false;
        //                    break;
        //                }
        //            }
        //            if (tekMi)
        //            {
        //                //Tek parça oldğ. için karıştırmaya gerek yok
        //                foreach (Rota.RotaParcasi rp in op.AltParca)
        //                {
        //                    DateTime? deger = Yukle(rp, DateTime.FromBinary(sonTarih.ToBinary()), recDerinlik + 1);
        //                        if (deger.HasValue)
        //                        {
        //                            //Yüklendi
        //                            sonTarih = deger.Value;
        //                        }
        //                        else
        //                        {
        //                            //Yüklenemedi
        //                            return null;
        //                        }
        //                }
        //            }
        //            else
        //            {
        //                //Operasyonsuz rotaparçalarını ayıkla.
        //                List<Rota.RotaParcasi> temizListe = temizle(op.AltParca);
        //                IEnumerable<IEnumerable<Rota.RotaParcasi>> perm = PermuteUtils.Permute<Rota.RotaParcasi>(temizListe, temizListe.Count);
        //                int i = 0;
        //                int optSira = -1;
        //                DateTime optTarih = new DateTime();
        //                optTarih = new DateTime();
        //                foreach (IEnumerable<Rota.RotaParcasi> sira in perm)
        //                {
        //                    DateTime tempTarih = DateTime.FromBinary(sonTarih.ToBinary());
        //                    foreach (Rota.RotaParcasi rp in sira)
        //                    {
        //                        DateTime? deger = Yukle(rp, DateTime.FromBinary(sonTarih.ToBinary()), recDerinlik + 1);
                              
        //                        if (deger.HasValue)
        //                        {
        //                            //Yüklendi
        //                            if (deger.Value < tempTarih)
        //                            {
        //                                tempTarih = DateTime.FromBinary(deger.Value.ToBinary());
        //                            }
        //                            /*if (deger > optTarih)
        //                            {
        //                                optTarih = deger.Value;
        //                                optSira = i;
        //                            }*/
        //                        }
        //                        else
        //                        {
        //                            //Yüklenemedi
        //                            break;
        //                        }
        //                    }
        //                    if (tempTarih>optTarih)
        //                    {
        //                        optTarih = DateTime.FromBinary(tempTarih.ToBinary());
        //                        optSira = i;
        //                    }
        //                    cizelge.SonrasiniGeriAl(recDerinlik + 1, grupNo);
        //                    i++;
        //                }
        //                if (optSira > -1)
        //                {
        //                    List<Rota.RotaParcasi> optimizeList = perm.Skip(optSira).First().ToList<Rota.RotaParcasi>();
                             
        //                    foreach (Rota.RotaParcasi rp in optimizeList)
        //                    {
        //                        DateTime? deger = Yukle(rp, DateTime.FromBinary(eldekiTarih.ToBinary()), recDerinlik + 1);
        //                        if (deger.HasValue)
        //                        {
        //                            sonTarih = deger.Value;
        //                        }
        //                        else
        //                        {
        //                            return null;
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //    }
        //    return sonTarih;
        //}

        private List<Rota.RotaParcasi> temizle(List<Rota.RotaParcasi> gelenListe)
        {
            //Gelen rota listesinde operasyonu olmayanları listeden siler ve yeni listeye atar eski listeye dokunulmaz
            List<Rota.RotaParcasi> liste = new List<Rota.RotaParcasi>();
            foreach (Rota.RotaParcasi rp in gelenListe)
            {
                if (rp.OperasyonList.Count>0)
                {
                    liste.Add(rp);
                }
            }
            return liste;
        }
        
        /*
        private bool Yukle(List<Rota.Operasyon> gelenOperasyon, DateTime bitTarih, int recDerinlik)
        {
            bool IsLoaded = false;
            DateTime EldekiSonTarih = bitTarih;
            foreach (Rota.Operasyon op in gelenOperasyon)
            {
                IsParcasi donenIsparcasi = Cizelge.ParcaEkle(cizelge, op, null, EldekiSonTarih, recDerinlik, grupNo,siparisBilgi);
                EldekiSonTarih = donenIsparcasi.BasTarihi;
                if (EldekiSonTarih < baslangicTarihi)
                {
                    IsLoaded = false;
                    return IsLoaded;
                }
                // operasyon listesindeki her operasyonun bir alt rota parçası olabilir. Onları geri yükleyelim.
                foreach (Rota.RotaParcasi rp in op.AltParca)
                {
                    if (Yukle(rp, EldekiSonTarih, recDerinlik + 1))
                    {
                        IsLoaded = true;
                    }
                    else
                    {
                        IsLoaded = false;
                        return IsLoaded;
                    }
                }
            }

            IsLoaded = true;
            return IsLoaded;
        }
        */
        public void GeriAl()
        {
            cizelge.GeriAl(null, grupNo);
        }
    }
}